package yz.com.javautil.dijkstrautil;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 将线路数据转换为Dijkstra图结构
 *
 * @author yuanzheng
 * @since 2022/11/2
 */
public class DijkstraGraphUtil {

    /**
     * 点列表
     */
    private static List<String> pointList = new ArrayList<>();

    /**
     * 稠密图实现
     */
    private static DijkstraImpl dijkstra;

    /**
     * 将线路数据转化为图
     *
     * @param lineGeomList 线路数据
     * @param directed     是否有向
     * @return 图对象
     */
    public static DijkstraImpl getGraphByLineGeomList(List<String> lineGeomList, boolean directed) {
        lineGeomList.forEach(DijkstraGraphUtil::addPointByLineGeomStr);
        dijkstra = new DijkstraImpl(pointList.size());
        lineGeomList.forEach(DijkstraGraphUtil::addEdgeByLineGeomStr);
        return dijkstra;
    }

    /**
     * 将线路数据放入pointList
     *
     * @param lineGeomStr 线路数据
     */
    private static void addPointByLineGeomStr(String lineGeomStr) {
        String[] pointStr = lineGeomStr.split(",");
        for (String point : pointStr) {
            if (pointList.indexOf(point) == -1) {
                pointList.add(point);
            }
        }
    }

    /**
     * 根据线路数据添加边
     *
     * @param lineGeomStr 线路数据
     */
    private static void addEdgeByLineGeomStr(String lineGeomStr) {
        String[] pointStr = lineGeomStr.split(",");
        int pointLength = pointStr.length;
        for (int i = 0; i < pointLength - 1; i++) {
            dijkstra.addEdge(pointList.indexOf(pointStr[i]), pointList.indexOf(pointStr[i + 1]));
        }
    }

    /**
     * 根据点座标获取最近点的index
     *
     * @param point 点座标
     * @return 最近点的index
     */
    public static int getNearestPointIndex(String point) {
        final AtomicReference<String>[] nearestPoint = new AtomicReference[]{new AtomicReference<>("")};
        final double[] distance = {10000.0};
        pointList.forEach(p -> {
            double pointDistance = getPointDistance(p, point);
            if (pointDistance < distance[0] && pointDistance != 0) {
                nearestPoint[0].set(p);
                distance[0] = pointDistance;
            }
        });
        return pointList.indexOf(nearestPoint[0].get());
    }

    /**
     * 计算两点之间的距离（忽略弧度）
     *
     * @param pointOne   点一
     * @param pointOther 另一个点
     * @return 两点直接的距离
     */
    private static double getPointDistance(String pointOne, String pointOther) {
        String[] pointOneArr = pointOne.split(" ");
        String[] pointOtherArr = pointOther.split(" ");
        return Math.sqrt(
                Math.abs(
                        (Double.parseDouble(pointOneArr[0]) - Double.parseDouble(pointOtherArr[0]))
                                * (Double.parseDouble(pointOneArr[0]) - Double.parseDouble(pointOtherArr[0]))
                                + (Double.parseDouble(pointOneArr[1]) - Double.parseDouble(pointOtherArr[1]))
                                * (Double.parseDouble(pointOneArr[1]) - Double.parseDouble(pointOtherArr[1]))
                )
        );
    }

    /**
     * 将index路径数据转换为point字符串
     *
     * @param pathIndex 路径的index数据
     * @return 路径字符串
     */
    public static String getLineGeomByPointIndex(Vector<Integer> pathIndex) {
        List<String> point = new ArrayList<>();
        pathIndex.forEach(index -> {
            point.add(pointList.get(index));
        });
        return String.join(",", point);
    }

    /**
     * 打印pointList数据（用于测试）
     */
    public static void showPointList() {
        for (int i = 0; i < pointList.size(); i++) {
            System.out.println(i + ":" + pointList.get(i));
        }
    }
}
